package org.leumasjaffe.initiativeTracker.distributed.controller;


import java.io.StringWriter;
import java.util.Hashtable;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.leumasjaffe.initiativeTracker.operator.CharacterExporter;
import org.w3c.dom.Node;

import edu.wpi.heineman.server.ClientState;
import edu.wpi.heineman.server.Server;
import edu.wpi.heineman.xml.Message;
import edu.wpi.heineman.client.IMessageHandler;


/**
 * Sample implementation of a protocol handler to respond to messages received from clients.
 * You should follow this template when designing YOUR protocol handler.
 * <p>
 * To avoid issues with multiple clients submitting requests concurrently,
 * simply make the {@link #process(ClientState, Message)} method synchronized.
 * This will ensure that no more than one server thread executes this method
 * at a time.
 */
@NonNullByDefault
public final class ServerProtocolFactory implements edu.wpi.heineman.server.ServerProtocolFactory{
	
	static Hashtable<String, IMessageHandler> controllers = new Hashtable<String, IMessageHandler>();
	
	static {
		controllers.put("turnRequest", new ChangeTurnHandler());
		controllers.put("damageRequest", new DamageHandler());
		controllers.put("surgeRequest", new SurgeHandler());
		controllers.put("newRequest", new CharacterHandler());
		controllers.put("killRequest", new KillHandler());
		controllers.put("killAllRequest", new KillAllHandler());
		controllers.put("delayRequest", new DelayHandler());
		controllers.put("rollRequest", new RollHandler());
		controllers.put("nullRequest", new NullRollHandler());
	}
	
	@SuppressWarnings("null")
	@Override
	public synchronized Message process(ClientState st, Message request) {
		Node child = request.contents.getFirstChild();
		String type = child.getLocalName();
		
		String xmlString;
		Message response;
		String game = child.getAttributes().getNamedItem("game").getNodeValue();
		if (type.equals("initiativeRequest")) {
			response = new UploadHandler().process(request.id(), game);
			st.setData(game);
			st.sendMessage(response);
		}
		else {
			controllers.get(type).newCopy().process(request);
			xmlString = Message.responseHeader(request.id()) + nodeToString(child)
					.replaceAll("Request", "Response") + "</response>";
			response = new Message(xmlString);	
			CharacterExporter.export(game);
			for (String id : Server.ids()) {
				ClientState cs = Server.getState(id);
				if (cs.getData().equals(game) && !id.equals(st.id()))
					if (!cs.sendMessage(response))
						cs.close();
			}
		}

		xmlString = Message.responseHeader(request.id()) + "<relayResponse/></response>";
		response = new Message(xmlString);
		
		return response;
	}
	
	@SuppressWarnings("null")
	private static String nodeToString(Node node) {
		 StringWriter sw = new StringWriter();
		 try {
		   Transformer t = TransformerFactory.newInstance().newTransformer();
		   t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
		   t.transform(new DOMSource(node), new StreamResult(sw));
		 } catch (TransformerException te) {
		   System.out.println("nodeToString Transformer Exception");
		 }
		 return sw.toString();
	}
}
